﻿using HPSocketCS;
using Milink.Core;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using Secair.Core;
using Secair.Core.Data;
using Models;
using Newtonsoft.Json;
using System.Runtime.InteropServices;
using System.Data;

namespace Secair_TCP_Server_GB
{
    public partial class FormRemote : Form
    {
        #region Definition
        private HttpServer httpServer;
        private TcpServer tcpServer;

        private HPSocket.ITcpClient _client;
        private readonly List<byte> _packetData = new List<byte>();
        delegate void AddLogHandler(string log);

        private bool tcpIsOpen = false;
        private bool httpIsOpen = false;
        private bool tcpPlatformIsOpen = false;
        private bool tcpPlatformNeedOpen = false;

        private Dictionary<string, byte[]> deviceFrame = new Dictionary<string, byte[]>();
        private Dictionary<string, byte> deviceVerNo = new Dictionary<string, byte>();

        private delegate void ShowMsg(string msg, string action);
        private ShowMsg ShowMsgDelegate;
        private int msgMaxWidth;
        private string strAppUrl = "http://api.22222.com/api/iotapi/ReceiveStandard";

        private bool blHttpToSecair = false;

        private const string param = "deviceCode={0}&equipmentSupplierCode={1}&command={2}&deviceTime={3}&messageData={4}&formatObject={5}";

        /// <summary>
        /// 最大封包长度
        /// </summary>
        private const int MaxPacketSize = 4096;

        //声明一个委托
        public delegate void dataGridView_GateWay_Update_Callback(GBCmd gbCmd, GBMessageEntity gbMessageEntity);
        //联网设备列表
        DataTable dt = new DataTable();
        #endregion

        #region FormRemote
        public FormRemote()
        {
            InitializeComponent();
            ShowMsgDelegate = new ShowMsg(showMsg);
            LogHelper.init(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));
            txtTcpPort.Text = ConfigurationManager.AppSettings["TcpPort"] ?? "14444";
            txtHttpPort.Text = ConfigurationManager.AppSettings["HttpPort"] ?? "24444";

            setButton(false, false);
            this.BackgroundImage = imgBackPr();
        }
        #endregion

        #region Form Move
        const int WM_NCLBUTTONDOWN = 0xA1;
        const int HT_CAPTION = 0x2;
        [DllImport("user32.dll")]
        static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);

        protected override void OnMouseDown(MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                this.Capture = false;
                SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
            }
            else
            {
                //this.Close();          // 右键可以退出
            }
        }
        #endregion

        #region Form Image
        private Image imgBackPr()
        {
            Image img = new System.Drawing.Bitmap(980, 558);
            Graphics g = Graphics.FromImage(img);
            g.Clear(Color.Transparent);
            try
            {
                g.DrawImage(Properties.Resources.main_Back, 0, 0, img.Width, img.Height);
                g.DrawImage(Properties.Resources.logo, 0, 0, 160, 40);
                g.DrawImage(Properties.Resources.title, 400, 8, 120, 24);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            return img;
        }
        #endregion

        #region Form Tools
        private void pic_Main_Close_MouseEnter(object sender, EventArgs e)
        {
            pic_Main_Close.BackgroundImage = Properties.Resources.form_CloseE;
        }

        private void pic_Main_Close_MouseLeave(object sender, EventArgs e)
        {
            pic_Main_Close.BackgroundImage = Properties.Resources.form_CloseN;
        }

        private void pic_Main_Close_Click(object sender, EventArgs e)
        {
            //this.Close();
            //Application.Exit();
            System.Environment.Exit(0);
        }

        private void pic_Main_Min_Click(object sender, EventArgs e)
        {
            this.WindowState = FormWindowState.Minimized;
        }

        private void pic_Main_Min_MouseEnter(object sender, EventArgs e)
        {
            pic_Main_Min.BackgroundImage = Properties.Resources.form_MinE;
        }

        private void pic_Main_Min_MouseLeave(object sender, EventArgs e)
        {
            pic_Main_Min.BackgroundImage = Properties.Resources.form_MinN;
        }
        #endregion

        #region FormRemote_FormClosing
        private void FormRemote_FormClosing(object sender, FormClosingEventArgs e)
        {
            try
            {
                if (tcpServer != null)
                {
                    tcpServer.Destroy();
                }

                if (httpServer != null)
                    httpServer.Destroy();
            }
            catch
            {

            }
        }
        #endregion 

        #region From-Btns

        #region btnStartHttp_Click
        private void btnStartHttp_Click(object sender, EventArgs e)
        {
            try
            {
                ushort.TryParse(txtHttpPort.Text, out ushort httpPort);
                if (httpPort < 1000) return;
                httpServer = new HttpServer
                {
                    IpAddress = "0.0.0.0",
                    Port = httpPort
                };
                //httpServer.OnHeadersComplete += new HttpEvent.OnHeadersCompleteEventHandler(Http_OnHeadersComplete);
                httpServer.OnBody += new HttpEvent.OnBodyEventHandler(Http_OnBody);
                httpServer.OnMessageComplete += new HttpEvent.OnMessageCompleteEventHandler(Http_OnMessageComplete);
                httpServer.OnParseError += new HttpEvent.OnParseErrorEventHandler(Http_OnParseError);
                httpServer.OnClose += new TcpServerEvent.OnCloseEventHandler(Http_OnClose);
                httpServer.OnShutdown += new TcpServerEvent.OnShutdownEventHandler(Http_OnShutdown);
                if (httpServer.Start())
                {
                    setButton(tcpIsOpen, true);
                    showMsg(string.Format("> {0}:{1}", httpServer.IpAddress, httpServer.Port), "http start");
                }
                else
                {
                    showMsg(string.Format("> {0}:{1} start error {2}:{3}", httpServer.IpAddress, httpServer.Port, httpServer.ErrorCode, httpServer.ErrorMessage), "http start");
                }
            }
            catch (Exception ex)
            {
                showMsg(ex.Message, "http start error");
                LogHelper.error("http start error", ex);
            }
        }
        #endregion

        #region btnStopHttp_Click
        private void btnStopHttp_Click(object sender, EventArgs e)
        {
            try
            {
                if (httpServer.Stop())
                {
                    setButton(tcpIsOpen, false);
                    showMsg(string.Format("> {0}:{1}", httpServer.IpAddress, httpServer.Port), "http stop");
                }
                else
                {
                    showMsg(string.Format("> {0}:{1} stop error {2}:{3}", httpServer.IpAddress, httpServer.Port, httpServer.ErrorCode, httpServer.ErrorMessage), "http stop");
                }
            }
            catch (Exception ex)
            {
                showMsg(ex.Message, "http stop error");
                LogHelper.error("http stop error", ex);
            }
        }
        #endregion

        #region btnStartTcp_Click
        private void btnStartTcp_Click(object sender, EventArgs e)
        {
            try
            {
                ushort.TryParse(txtTcpPort.Text, out ushort tcpPort);
                if (tcpPort < 1000) return;
                tcpServer = new TcpServer
                {
                    SocketBufferSize = 1348,
                    KeepAliveTime = 1000,
                    KeepAliveInterval = 1000,
                    IpAddress = "0.0.0.0",
                    Port = tcpPort
                };
                //server.OnPrepareListen += new TcpServerEvent.OnPrepareListenEventHandler(OnPrepareListen);
                tcpServer.OnAccept += new TcpServerEvent.OnAcceptEventHandler(Tcp_OnAccept);
                tcpServer.OnSend += new TcpServerEvent.OnSendEventHandler(Tcp_OnSend);
                ////server.OnPointerDataReceive += new TcpServerEvent.OnPointerDataReceiveEventHandler(OnPointerDataReceive);
                tcpServer.OnReceive += new TcpServerEvent.OnReceiveEventHandler(Tcp_OnReceive);
                tcpServer.OnClose += new TcpServerEvent.OnCloseEventHandler(Tcp_OnClose);
                tcpServer.OnShutdown += new TcpServerEvent.OnShutdownEventHandler(Tcp_OnShutdown);
                if (tcpServer.Start())
                {
                    setButton(true, httpIsOpen);
                    showMsg(string.Format("> {0}:{1}", tcpServer.IpAddress, tcpServer.Port), "tcp start");
                }
                else
                {
                    showMsg(string.Format("> {0}:{1} start error {2}:{3}", tcpServer.IpAddress, tcpServer.Port, tcpServer.ErrorCode, tcpServer.ErrorMessage), "tcp start");
                }
            }
            catch (Exception ex)
            {
                showMsg(ex.Message, "tcp start error");
                LogHelper.error("tcp start error", ex);
            }
        }
        #endregion

        #region btnStopTcp_Click
        private void btnStopTcp_Click(object sender, EventArgs e)
        {
            try
            {
                if (tcpServer.Stop())
                {
                    setButton(false, httpIsOpen);
                    showMsg(string.Format("> {0}:{1}", tcpServer.IpAddress, tcpServer.Port), "tcp stop");
                }
                else
                {
                    showMsg(string.Format("> {0}:{1} stop error {2}:{3}", tcpServer.IpAddress, tcpServer.Port, tcpServer.ErrorCode, tcpServer.ErrorMessage), "tcp stop");
                }
            }
            catch (Exception ex)
            {
                showMsg(ex.Message, "tcp stop error");
                LogHelper.error("tcp stop error", ex);
            }
        }
        #endregion

        #region btnPlatformStartTcp_Click
        private async void btnTcpPlatformStart_Click(object sender, EventArgs e)
        {
            try
            {
                tcpPlatformNeedOpen = true;
                ushort.TryParse(txtTcpPlatformPort.Text, out ushort tcpPlatformPort);
                if (tcpPlatformPort < 1000) return;
                _client = new HPSocket.Tcp.TcpClient
                {
                    SocketBufferSize = 4096, // 4K
                    Async = true,
                    Address = txtTcpPlatformIp.Text,
                    Port = tcpPlatformPort
                };
                // 事件绑定
                _client.OnPrepareConnect += OnPrepareConnect;
                _client.OnConnect += OnConnect;
                _client.OnReceive += OnReceive;
                _client.OnClose += OnClose;

                if (!tcpPlatformIsOpen)
                {
                    // 连接到目标服务器
                    if (!_client.Connect())
                    {
                        throw new Exception($"error code: {_client.ErrorCode}, error message: {_client.ErrorMessage}");
                    }

                    tcpPlatformIsOpen = true;
                    btnTcpPlatformStart.Enabled = !tcpPlatformIsOpen;
                    btnTcpPlatformStop.Enabled = tcpPlatformIsOpen;

                    // 等待服务停止
                    await _client.WaitAsync();

                }
                else
                {
                    AddLog($"exception: Already Open");
                }
            }
            catch (Exception ex)
            {
                AddLog($"exception: {ex.Message}");
            }
        }
        #endregion

        #region btnPlatformStopTcp_Click
        private async void btnTcpPlatformStop_Click(object sender, EventArgs e)
        {
            try
            {
                tcpPlatformNeedOpen = false;
                // 断开连接
                await _client.StopAsync();
                tcpPlatformIsOpen = false;
                btnTcpPlatformStart.Enabled = !tcpPlatformIsOpen;
                btnTcpPlatformStop.Enabled = tcpPlatformIsOpen;
            }
            catch (Exception ex)
            {
                AddLog($"exception: {ex.Message}");
            }
        }
        #endregion

        #region setButton
        private void setButton(bool tcpIsOpen, bool httpIsOpen)
        {
            this.tcpIsOpen = tcpIsOpen;

            txtTcpPort.Enabled = !this.tcpIsOpen;       //初始状态
            btnStartTcp.Enabled = !this.tcpIsOpen;      //初始状态
            btnStopTcp.Enabled = this.tcpIsOpen;

            this.httpIsOpen = httpIsOpen;
            txtHttpPort.Enabled = !this.httpIsOpen;     //初始状态
            btnStartHttp.Enabled = !this.httpIsOpen;    //初始状态
            btnStopHttp.Enabled = this.httpIsOpen;
        }

        #endregion

        #endregion

        #region HTTP Tools

        #region Http_OnBody
        private HttpParseResult Http_OnBody(IntPtr connectId, byte[] bytes)
        {
            string postBody = httpServer.GetExtra<string>(connectId);
            if (string.IsNullOrWhiteSpace(postBody)) postBody = "";
            postBody += Encoding.GetEncoding("gb2312").GetString(bytes).TrimEnd('\0').Replace('\0', '-');
            showMsg("body:" + bytes.Length + ":" + postBody, "debug http request body");
            httpServer.SetExtra(connectId, postBody);
            return HttpParseResult.Ok;
        }
        #endregion

        #region Http_OnMessageComplete
        private HttpParseResult Http_OnMessageComplete(IntPtr connectId)
        {
            AjaxResult result = new AjaxResult()
            {
                success = true,
                message = "ok"
            };
            try
            {
                string path = httpServer.GetUrlField(connectId, HttpUrlField.Path);
                if (path.ToLower() == "/secairgb")
                {
                    string queryString = httpServer.GetUrlField(connectId, HttpUrlField.QueryString);
                    Dictionary<string, string> requestParam = SaiKeUtility.getQueryParam(queryString);

                    string postBody = httpServer.GetExtra<string>(connectId);
                    if (!string.IsNullOrWhiteSpace(postBody))
                    {
                        requestParam.leftMerge(SaiKeUtility.getQueryParam(postBody));
                    }

                    showMsg(requestParam.serialize(), "debug http request");

                    //判断method
                    string request_method = requestParam.ContainsKey("method") ? requestParam["method"] : "";
                    if (string.IsNullOrWhiteSpace(request_method))
                    {
                        result = new AjaxResult(false, "miss method");
                    }
                    else
                    {
                        //判断deviceId
                        string request_deviceId = requestParam.ContainsKey("deviceId") ? requestParam["deviceId"] : "";
                        if (string.IsNullOrWhiteSpace(request_deviceId))
                        {
                            result = new AjaxResult(false, "miss deviceId");
                        }
                        else
                        {
                            //showMsg(string.Format("> {0}:{1},{2} method:{3}", httpServer.IpAddress, httpServer.Port, connectId, method), "http request");
                            //其它参数
                            string request_host_str = requestParam.ContainsKey("host") ? requestParam["host"] : "";
                            string request_loop_str = requestParam.ContainsKey("loop") ? requestParam["loop"] : "";
                            string request_adress_str = requestParam.ContainsKey("adress") ? requestParam["adress"] : "";
                            Byte.TryParse(request_host_str, out byte request_host);
                            Byte.TryParse(request_loop_str, out byte request_loop);
                            Byte.TryParse(request_adress_str, out byte request_adress);
                            string request_param = requestParam.ContainsKey("param") ? requestParam["param"] : "";
                            bool cmdResult = false;
                            switch (request_method.ToLower())
                            {
                                case "61":
                                    break;
                                case "62":
                                    break;
                                case "63":
                                    break;
                                case "64":
                                    break;
                                case "65":
                                    break;
                                case "66":
                                    break;
                                case "67":
                                    break;
                                case "81":
                                    break;
                                case "84":
                                    break;
                                case "85":
                                    break;
                                case "86":
                                    break;
                                case "88":
                                    break;
                                case "89":
                                    break;
                                case "90":
                                    cmdResult = true;
                                    break;
                                case "test10k":
                                    break;
                                case "154_9":
                                    break;
                                default:
                                    break;
                            }
                            result = new AjaxResult(cmdResult, string.Format("deviceId:{0},command:{1}", request_deviceId, request_method));
                        }
                    }
                    showMsg(result.serialize(), "http request");
                }
            }
            catch (Exception ex)
            {
                showMsg(ex.Message, "http message error");
                result = new AjaxResult(false, ex.Message);
                LogHelper.error("http message error", ex);
            }
            byte[] responseBody = Encoding.UTF8.GetBytes(result.serialize());
            httpServer.SendResponse(connectId, HttpStatusCode.Ok, "", null, responseBody, responseBody.Length);
            httpServer.Release(connectId);
            return HttpParseResult.Ok;
        }
        #endregion

        #region Http_OnParseError
        private HttpParseResult Http_OnParseError(IntPtr connectId, int errorCode, string errorDesc)
        {
            showMsg(string.Format("> {0}:{1}", errorCode, errorDesc), "http parse error");
            httpServer.Release(connectId);
            return HttpParseResult.Ok;
        }
        #endregion

        #region Http_OnClose
        private HandleResult Http_OnClose(TcpServer server, IntPtr connectId, SocketOperation enOperation, int errorCode)
        {
            if (errorCode == 0)
                showMsg(string.Format("> {0}:{1},{2}", server.IpAddress, server.Port, connectId), "http close");
            else
                showMsg(string.Format("> {0}:{1},{2} -> op:{3},code:{4}", server.IpAddress, server.Port, connectId, enOperation, errorCode), "http close error");
            if (server.GetExtra(connectId) != null)
            {
                if (server.RemoveExtra(connectId))
                    showMsg(string.Format("> {0}:{1},{2} -> remove extra", server.IpAddress, server.Port, connectId), "http close");
                else
                    showMsg(string.Format("> {0}:{1},{2} -> remove extra fail", server.IpAddress, server.Port, connectId), "http close error");
            }
            return HandleResult.Ok;
        }
        #endregion

        #region Http_OnShutdown
        private HandleResult Http_OnShutdown(TcpServer server)
        {
            showMsg(string.Format("> {0}:{1}", server.IpAddress, server.Port), "http shutdown");
            return HandleResult.Ok;
        }
        #endregion

        #endregion   

        #region TCP(Trans) Tools

        #region Tcp_OnAccept
        private HandleResult Tcp_OnAccept(TcpServer server, IntPtr connectId, IntPtr pClient)
        {
            try
            {
                string ip = string.Empty;
                ushort port = 0;
                if (server.GetRemoteAddress(connectId, ref ip, ref port))
                {
                    showMsg(string.Format("> {0}:{1},{2} -> {3}:{4}", server.IpAddress, server.Port, connectId, ip, port), "accept");
                }
                else
                {
                    throw new Exception(string.Format("> {0}:{1},{2} -> get client address error", server.IpAddress, server.Port, connectId));
                }
                TcpClientInfo tcpClientInfo = new TcpClientInfo
                {
                    connectId = connectId,
                    ip = ip,
                    port = port,
                    deviceId = ""
                };
                if (server.SetExtra(connectId, tcpClientInfo) == false)
                {
                    throw new Exception(string.Format("> {0}:{1},{2} -> {3}:{4} set extra fail", server.IpAddress, server.Port, connectId, ip, port));
                }
                //主动查询151
                //send151(connectId, ip + port, 0);

                return HandleResult.Ok;
            }
            catch (Exception ex)
            {
                showMsg(ex.Message, "accept error");
                LogHelper.error("accept error", ex);
                return HandleResult.Ignore;
            }
        }
        #endregion

        #region Tcp_OnSend
        private HandleResult Tcp_OnSend(TcpServer server, IntPtr connectId, byte[] bytes)
        {
            try
            {
                showMsg(Milink.Core.ByteHelper.bytesToHexString(bytes, "~", 16), "debug send");
                if (server.GetExtra(connectId) is TcpClientInfo tcpClientInfo)
                {
                    showMsg(string.Format("> {0}:{1},{2} -> {3}:{4} ({5} bytes)", server.IpAddress, server.Port, connectId, tcpClientInfo.ip, tcpClientInfo.port, bytes.Length), "send");
                }
                else
                {
                    showMsg(string.Format("> {0}:{1},{2} -> ({3} bytes)", server.IpAddress, server.Port, connectId, bytes.Length), "send");
                }
                return HandleResult.Ok;
            }
            catch (Exception ex)
            {
                showMsg(ex.Message, "send error");
                LogHelper.error("send error", ex);
                return HandleResult.Ignore;
            }
        }
        #endregion

        #region Tcp_OnReceive
        private HandleResult Tcp_OnReceive(TcpServer server, IntPtr connectId, byte[] bytes)
        {
            try
            {
                showMsg(Milink.Core.ByteHelper.bytesToHexString(bytes, ",", 16), "debug receive");

                //国标协议基础查验
                string[] datas = Secair.Core.Tool.GBProtocolAnalysis.CheckGBProtocol(bytes);
                if (datas.Length == 0)
                    return HandleResult.Ignore;

                if (server.GetExtra(connectId) is TcpClientInfo tcpClientInfo)
                {
                    showMsg(string.Format("> {0}:{1},{2} -> {3}:{4} ({5} bytes)", server.IpAddress, server.Port, connectId, tcpClientInfo.ip, tcpClientInfo.port, bytes.Length), "receive");

                    foreach (string data in datas)
                    {
                        string strDataAdd = data.StartsWith("4040") ? data : "4040" + data;
                        strDataAdd = strDataAdd.EndsWith("2323") ? strDataAdd : strDataAdd + "2323";

                        if (!Secair.Core.Tool.GBProtocolAnalysis.CheckGBProtocolCS(Secair.Core.ByteHelper.hexStringToBytes(strDataAdd)))
                            return HandleResult.Ignore;

                        GBCmd gbCmd = new GBCmd
                        {
                            messageData = strDataAdd
                        };
                        //对payload进行拆解
                        GBMessageEntity gbMessageEntity = GBMessageFormat.MessageStringConvertEntity(gbCmd.messageData);
                        gbCmd.eventTime = Secair.Core.Tool.GBStructureAnalysis.AnalysisDateTimeGB(Secair.Core.ByteHelper.hexStringToBytes(gbMessageEntity.MessageDateTime));
                        gbCmd.deviceId = Secair.Core.ByteHelper.hexStringToIAdress(gbMessageEntity.Source).ToString();
                        tcpClientInfo.deviceId = gbCmd.deviceId;

                        //数据处理，控制台响应
                        //URL读取
                        //string strOrleansServer = System.Configuration.ConfigurationManager.AppSettings["AppUrl"];
                        /*---总队平台全部转发---*/
                        if (tcpPlatformIsOpen)
                            sendToPlatform(PacketType.Echo, gbCmd.messageData);
                        switch (gbMessageEntity.Command)
                        {
                            //控制命令
                            case 0://预留
                                break;
                            case 1://控制命令
                                   //处理


                                //返回  
                                break;
                            case 2://发送数据
                                   //处理
                                Data2 _data = GBCommandHandler.handler2(gbMessageEntity.Type, gbMessageEntity);
                                gbCmd.formatObject = _data.data;
                                gbCmd.equipmentSupplierCode = connectId.ToString();
                                gbCmd.command = gbMessageEntity.Type;

                                showMsg(string.Format("analysis:{0}", _data.msgLog), "analysis");

                                /*---返回 根据type（回复类型） 返回命令 平台自动回复(无总队平台)---*/
                                if (!tcpPlatformIsOpen)
                                {
                                    byte[] sendByte = null;
                                    switch (_data.type)
                                    {
                                        case -1:
                                            break;
                                        case 6:
                                            sendByte = GBCommandSend.send6(gbMessageEntity, gbCmd.messageData);
                                            send(connectId, "", sendByte);
                                            break;
                                        default:
                                            sendByte = GBCommandSend.send3(gbMessageEntity, gbCmd.messageData);
                                            send(connectId, "", sendByte);
                                            break;
                                    }
                                }
                                //返回 根据command（转发类型）  转发命令
                                string body = string.Format(param, gbCmd.deviceId, "", gbMessageEntity.Type, gbCmd.eventTime, gbCmd.messageData, gbCmd.formatObject.serialize());
                                switch (_data.command)
                                {
                                    case -1:
                                        break;
                                    default:
                                        GBCommandHandler.sendToApp(strAppUrl, body);


                                        AddLogSecair($"{gbCmd.deviceId}-SendToApp(), protocol: {gbMessageEntity.Type}");
                                        break;
                                }
                                dataGridView_GateWay_Update(gbCmd, gbMessageEntity);
                                break;
                            case 3://确认 对应命令2的响应
                                   //处理

                                //返回

                                break;
                            case 4://请求
                                   //处理

                                //返回

                                break;
                            case 5://应答  对应命令4  对下行查询的应答
                                   //处理-查岗应答

                                //返回
                                break;
                            case 6://否认  对应命令2的响应
                                   //处理

                                //返回

                                break;
                            default:
                                //TODO  回复 不可识别的命令字节

                                break;
                        }
                        //showMsg(string.Format("deviceId:{0},command:{1}", saikeCmd.deviceId, saikeCmd.command), "data");
                        /*if (string.IsNullOrWhiteSpace(tcpClientInfo.deviceId))
                        {
                            //主动查询151
                            //send151(connectId, tcpClientInfo.ip + tcpClientInfo.port, 0);
                        }
                        else
                        {
                            throw new Exception(string.Format("> {0}:{1},{2} -> null ({3} bytes)", server.IpAddress, server.Port, connectId, bytes.Length));
                        }*/
                    }
                }
                return HandleResult.Ok;
            }
            catch (Exception ex)
            {

                showMsg(ex.Message, "receive error");
                LogHelper.error("receive error", ex);
                return HandleResult.Ignore;
            }
        }
        #endregion

        #region Tcp_OnClose
        private HandleResult Tcp_OnClose(TcpServer server, IntPtr connectId, SocketOperation enOperation, int errorCode)
        {
            if (errorCode == 0)
                showMsg(string.Format("> {0}:{1},{2}", server.IpAddress, server.Port, connectId), "tcp close");
            else
                showMsg(string.Format("> {0}:{1},{2} -> op:{3},code:{4}", server.IpAddress, server.Port, connectId, enOperation, errorCode), "tcp close error");
            if (server.GetExtra(connectId) is TcpClientInfo tcpClientInfo)
            {
                GBCmd saikeCmd = new GBCmd
                {
                    deviceId = tcpClientInfo.deviceId,
                    //command = 0xFF,
                    eventTime = DateTime.Now,
                    messageData = "Tcp Close",
                };

                //SaiKeUtility.sendToApp(txtAppUrl.Text, saikeCmd.serialize(), "");

                GBCommandHandler.sendToApp(strAppUrl, saikeCmd.serialize());
                AddLogSecair($"TcpClose(), connectId: {connectId}");

                /*if (deviceFrame.ContainsKey(tcpClientInfo.deviceId))
                {
                    deviceFrame.Remove(tcpClientInfo.deviceId);
                }
                if (deviceFrame.ContainsKey(tcpClientInfo.ip + tcpClientInfo.port))
                {
                    deviceFrame.Remove(tcpClientInfo.ip + tcpClientInfo.port);
                }*/

                if (server.RemoveExtra(connectId))
                    showMsg(string.Format("> {0}:{1},{2} -> remove extra", server.IpAddress, server.Port, connectId), "tcp close");
                else
                    showMsg(string.Format("> {0}:{1},{2} -> remove extra fail", server.IpAddress, server.Port, connectId), "tcp close error");
            }
            return HandleResult.Ok;
        }
        #endregion

        #region Tcp_OnShutdown
        private HandleResult Tcp_OnShutdown(TcpServer server)
        {
            showMsg(string.Format("> {0}:{1}", server.IpAddress, server.Port), "tcp shutdown");
            return HandleResult.Ok;
        }
        #endregion

        #endregion

        #region TCP(Platform) Tools
        private async void ConnectToPlatform()
        {
            ushort.TryParse(txtTcpPlatformPort.Text, out ushort tcpPlatformPort);
            if (tcpPlatformPort < 1000) return;
            _client = new HPSocket.Tcp.TcpClient
            {
                SocketBufferSize = 4096, // 4K
                Async = true,
                Address = txtTcpPlatformIp.Text,
                Port = tcpPlatformPort
            };
            // 事件绑定
            _client.OnPrepareConnect += OnPrepareConnect;
            _client.OnConnect += OnConnect;
            _client.OnReceive += OnReceive;
            _client.OnClose += OnClose;

            while (!tcpPlatformIsOpen)
            {
                // 连接到目标服务器
                try
                {
                    Thread.Sleep(3000);
                    if (!_client.Connect())
                    {
                        throw new Exception($"error code: {_client.ErrorCode}, error message: {_client.ErrorMessage}");
                    }

                    tcpPlatformIsOpen = true;
                    btnTcpPlatformStart.Enabled = !tcpPlatformIsOpen;
                    btnTcpPlatformStop.Enabled = tcpPlatformIsOpen;

                    // 等待服务停止
                    await _client.WaitAsync();
                }
                catch (Exception ex)
                {
                    AddLog($"exception: {ex.Message}");
                }
            }
        }

        // ReSharper disable once InconsistentNaming
        private HPSocket.HandleResult OnPrepareConnect(HPSocket.IClient sender, IntPtr socket)
        {
            return HPSocket.HandleResult.Ok;
        }

        // ReSharper disable once InconsistentNaming
        private HPSocket.HandleResult OnConnect(HPSocket.IClient sender)
        {
            AddLog("OnConnect()");
            _packetData.Clear();
            return HPSocket.HandleResult.Ok;
        }

        // ReSharper disable once InconsistentNaming
        private HPSocket.HandleResult OnReceive(HPSocket.IClient sender, byte[] data)
        {
            /*if (chkDebugPlatform.Checked)
                AddLog($"OnReceive(), data: {data.Length},{Secair.Core.ByteHelper.bytesToHexString(data)}");*/
            return OnProcessFullPacket(data);
        }

        // ReSharper disable once InconsistentNaming
        private HPSocket.HandleResult OnClose(HPSocket.IClient sender, HPSocket.SocketOperation socketOperation, int errorCode)
        {
            _packetData.Clear();
            AddLog($"OnClose(), socket operation: {socketOperation}, error code: {errorCode}");
            if (tcpPlatformNeedOpen)
            {
                tcpPlatformIsOpen = false;
                ConnectToPlatform();
            }
            return HPSocket.HandleResult.Ok;
        }

        // ReSharper disable once InconsistentNaming
        private HPSocket.HandleResult OnProcessFullPacket(byte[] bytes)
        {
            string[] datas = Secair.Core.Tool.GBProtocolAnalysis.CheckGBProtocol(bytes);
            if (datas.Length == 0)
            {
                AddLog($"exception(dataGB error)");
                return HPSocket.HandleResult.Ignore;
            }
            AddLog($"recevie(), data: {bytes.Length},{Secair.Core.ByteHelper.bytesToHexString(bytes)}");

            try
            {
                foreach (string data in datas)
                {
                    string strDataAdd = data.StartsWith("4040") ? data : "4040" + data;
                    strDataAdd = strDataAdd.EndsWith("2323") ? strDataAdd : strDataAdd + "2323";
                    GBCmd gbCmd = new GBCmd
                    {
                        messageData = strDataAdd
                    };
                    //对GB协议进行拆解
                    GBMessageEntity gbMessageEntity = GBMessageFormat.MessageStringConvertEntity(gbCmd.messageData);
                    gbCmd.eventTime = Secair.Core.Tool.GBStructureAnalysis.AnalysisDateTimeGB(Secair.Core.ByteHelper.hexStringToBytes(gbMessageEntity.MessageDateTime));
                    gbCmd.deviceId = Secair.Core.ByteHelper.hexStringToIAdress(gbMessageEntity.Target).ToString() ;
                    //Console.WriteLine("Platform time:" + gbCmd.eventTime + " deviceId:" + gbCmd.deviceId);
                    //全部统一处理
                    if (tcpServer.IsStarted)
                        send(gbCmd.deviceId, Secair.Core.ByteHelper.hexStringToBytes(gbCmd.messageData));
                    switch (gbMessageEntity.Command)
                    {
                        case 1://控制命令
                            Data1 _data = GBCommandHandler.handler1(gbMessageEntity.Type, gbMessageEntity);
                            gbCmd.formatObject = _data.data;
                            gbCmd.command = (byte)_data.command;

                            //showMsg(string.Format("analysis:{0}", _data.msgLog), "analysis");
                            AddLog($"{gbCmd.deviceId}-log: {_data.msgLog}");

                            //返回 根据type（回复类型）  返回命令--------暂停自行处理
                            /*byte[] sendByte = null;
                            switch (_data.type)
                            {
                                case -1:
                                    break;
                                case 6:
                                    break;
                                default:
                                    sendByte = GBCommandSend.send3(gbMessageEntity, gbCmd.messageData);
                                    sendToPlatform(PacketType.Echo, sendByte);
                                    break;
                            }
                            if ((gbMessageEntity.Type == 90 || gbMessageEntity.Type == 91) && tcpServer != null)
                            {
                                if (tcpServer.IsStarted)
                                {
                                    send(gbCmd.deviceId, Secair.Core.ByteHelper.hexStringToBytes(gbCmd.messageData));
                                }
                            }*/
                            break;
                        default:
                            break;
                    }
                }
                var result = HPSocket.HandleResult.Ok;
                return result;
            }
            catch (Exception ex)
            {
                AddLog($"exception(receive error): {ex.Message}");
                return HPSocket.HandleResult.Ignore;
            }
        }
        #endregion

        #region Tool-showMsg(TCP_Trans And HTTP)
        private void showMsg(string msg, string action)
        {
            if (lbxMsg.InvokeRequired)
            {
                lbxMsg.Invoke(ShowMsgDelegate, msg, action);
            }
            else
            {
                try
                {
                    if (!chkDebug.Checked && action.IndexOf("debug") > -1) return;
                    LogHelper.info(string.Format("{0}\r\n{1}", action, msg));
                    if (!chkLite.Checked || action == "data" || action == "http request" || action.IndexOf("error") > -1)
                    {
                        while (lbxMsg.Items.Count > 1000)
                        {
                            lbxMsg.Items.RemoveAt(0);
                        }
                        lbxMsg.Items.Add(" ~  " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff") + " ~  " + action);
                        lbxMsg.Items.AddRange(msg.Split(new string[] { Environment.NewLine }, StringSplitOptions.None));
                        lbxMsg.TopIndex = lbxMsg.Items.Count - (lbxMsg.Height / lbxMsg.ItemHeight) + 3;
                        msgMaxWidth = 0;
                        foreach (string item in lbxMsg.Items)
                        {
                            msgMaxWidth = Math.Max(msgMaxWidth, (int)lbxMsg.CreateGraphics().MeasureString(item, lbxMsg.Font).Width);
                        }
                        lbxMsg.HorizontalExtent = msgMaxWidth + 10;
                    }
                }
                catch (Exception ex)
                {
                    lbxMsg.Items.Clear();
                    LogHelper.error("showMsg Error", ex);
                }
            }
        }
        #endregion

        #region Tool-send(Trans)
        private bool send(string deviceId, byte[] frame)
        {
            IntPtr connectId = IntPtr.Zero;
            IntPtr[] allConnectId = tcpServer.GetAllConnectionIDs();
            if (allConnectId != null)
            {
                foreach (IntPtr connid in allConnectId)
                {
                    if (tcpServer.GetExtra(connid) is TcpClientInfo tcpClientInfo)
                    {
                        if (tcpClientInfo.deviceId == deviceId)
                        {
                            connectId = connid;
                            break;
                        }
                    }
                }
            }
            if (connectId == IntPtr.Zero)
                return false;
            else
                return send(connectId, deviceId, frame);
        }
        private bool send(IntPtr connectId, string deviceId, byte[] frame, byte ver_no = 0xFF)
        {
            if (frame.Length < 30) return false;

            return tcpServer.Send(connectId, frame, frame.Length);
        }
        #endregion

        #region Tool-showLog(Platform)
        private void AddLog(string log)
        {
            if (txtLog.IsDisposed)
            {
                return;
            }

            // 从ui线程去操作ui
            if (txtLog.InvokeRequired)
            {
                txtLog.Invoke(new AddLogHandler(AddLog), log);
            }
            else
            {
                if (txtLog.TextLength > 10000)
                    txtLog.Text = "";
                string strLog = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {log}\r\n";
                if (chkDebugPlatform.Checked)
                    txtLog.AppendText(strLog);
                Secair.Core.Log.LogWrite.LogWritePlatform(strLog);
            }
        }

        private void AddLogSecair(string log)
        {
            if (txtLogSecair.IsDisposed)
                return;
            // 从ui线程去操作ui
            if (txtLogSecair.InvokeRequired)
                txtLogSecair.Invoke(new AddLogHandler(AddLogSecair), log);
            else
            {
                if (txtLogSecair.TextLength > 10000)
                    txtLogSecair.Text = "";
                string strLog = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {log}\r\n";
                if (chkSecairLog.Checked)
                    txtLogSecair.AppendText(strLog);
                Secair.Core.Log.LogWrite.LogWriteSecair(strLog);

            }
        }
        #endregion

        #region Tool-send(Platform)
        /// <summary>
        /// 发送数据(TCP,到外部平台)
        /// </summary>
        /// <param name="type"></param>
        /// <param name="data"></param>
        private void sendToPlatform(PacketType type, string data)
        {
            if (!_client.HasStarted)
            {
                return;
            }

            // 组织封包, 取得要发送的数据
            var packet = new Packet
            {
                Type = type,
                Data = data,
            };

            //var bytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(packet));
            var bytes = Secair.Core.ByteHelper.hexStringToBytes(data);

            // 发送数据到服务器
            // 发送实际数据, 发送失败断开连接
            if (!_client.Send(bytes, bytes.Length))
            {
                _client.Stop();
                AddLog($"sendToPlatform(), fail");
            }
            else
            {
                AddLog($"sendToPlatform(), data: {bytes.Length},{data}");
            }
        }

        private void sendToPlatform(PacketType type, byte[] data)
        {
            if (!_client.HasStarted)
            {
                return;
            }

            // 发送数据到服务器
            // 发送实际数据, 发送失败断开连接
            if (!_client.Send(data, data.Length))
            {
                _client.Stop();
                AddLog($"sendToPlatform(), fail");
            }
            else
            {
                AddLog($"sendToPlatform(), data: {Secair.Core.ByteHelper.bytesToHexString(data)}");
            }
        }
        #endregion

        #region Tool-ack
        private void ack(IntPtr connectId, string deviceId, byte ver_no, byte cmd)
        {
            byte[] ackFrame = new byte[]
            {
                0x53,0x4E,
                0x00,0x00,  //长度
                0x10,       //版本流水号
                0xFA,       //命令250
                0x01,       //0-错误 1-正确 2-不合法
                cmd,        //原始命令
                0x00,
                0x00,
                0x00        //crc
            };
            send(connectId, deviceId, ackFrame, ver_no);
        }
        #endregion

        #region Tool-getLastSerialNo
        private byte getLastSerialNo(string deviceId)
        {
            if (!deviceVerNo.ContainsKey(deviceId)) deviceVerNo[deviceId] = 0xFF;
            return deviceVerNo[deviceId];
        }
        #endregion

        #region Tool-getNextSerialNo
        private byte getNextSerialNo(string deviceId)
        {
            deviceVerNo[deviceId] = (byte)((getLastSerialNo(deviceId) + 1) & 0xF | 0x10);
            return deviceVerNo[deviceId];
        }
        #endregion

        #region Tool-tinyWait
        private void tinyWait(long duration)
        {
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            tinyWait(duration, stopwatch);
            stopwatch.Stop();
        }
        private void tinyWait(long duration, Stopwatch stopwatch)
        {
            long current = stopwatch.ElapsedMilliseconds;
            while ((stopwatch.ElapsedMilliseconds - current) < duration)
            {
                Thread.Sleep(1);
            }
        }
        #endregion

        #region Tool-lbxMsg_DrawItem
        private void lbxMsg_DrawItem(object sender, DrawItemEventArgs e)
        {
            if (e.Index >= 0)
            {
                ListBox listBox = sender as ListBox;
                e.DrawBackground();
                Brush mybsh = Brushes.Black;
                if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
                {
                    mybsh = Brushes.White;
                }
                else if (listBox.Items[e.Index].ToString().StartsWith(" ~  "))
                {
                    mybsh = Brushes.Blue;
                }
                e.DrawFocusRectangle();
                e.Graphics.DrawString(listBox.Items[e.Index].ToString(), e.Font, mybsh, e.Bounds, StringFormat.GenericDefault);
            }
        }
        #endregion

        #region dataGridView_GateWay
        private void dataGridView_GateWay_Update(GBCmd gbCmd, GBMessageEntity gbMessageEntity)
        {
            if (this.dataGridView_GateWay.InvokeRequired)
            {
                this.dataGridView_GateWay.Invoke(new dataGridView_GateWay_Update_Callback(dataGridView_GateWay_Update), new object[] { gbCmd, gbMessageEntity });
                return;
            }
            try
            {
                //Console.WriteLine("dataGridView_GateWay_Update():" + gbCmd.eventTime);

                bool blExist = false;
                //Byte[] DestinationAddress = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
                //byte[] bytDat = Secair.Core.ByteHelper.hexStringToBytes(gbMessageEntity.Source);
                //Array.Copy(bytDat, 0, DestinationAddress, 0, 6);
                //ulong iAdress = BitConverter.ToUInt64(DestinationAddress, 0);
                foreach (DataGridViewRow dr in dataGridView_GateWay.Rows)
                {
                    if (dr.Cells[2].Value.ToString().Equals(gbCmd.deviceId.ToString()))
                    {
                        dr.Cells[0].Value = gbCmd.equipmentSupplierCode;
                        dr.Cells[3].Value = gbCmd.eventTime;
                        dr.Cells[4].Value = DateTime.Now;
                        dr.Cells[6].Value = gbMessageEntity.Command + "," + gbMessageEntity.Type;
                        blExist = true;
                        break;
                    }
                }
                if (!blExist)
                    dataGridView_GateWay.Rows.Add(gbCmd.equipmentSupplierCode, "---", gbCmd.deviceId, gbCmd.eventTime, DateTime.Now, "", gbMessageEntity.Command + "," + gbMessageEntity.Type, "");
            }
            catch
            { }

            /*DataTable dt = this.Fant_Xml.Get_ReadXml_Tabel(this.Fant_Xml.strFant_GateWay);
            DataRow dr = dt.Rows.Find(Id);
            if (dr == null) return;
            dr["zd_RecingDate_Time"] = DateTime.Now;*/
        }
        #endregion

        #region Labels
        private void lblValue_MouseEnter(object sender, EventArgs e)
        {
            ((Label)sender).Cursor = System.Windows.Forms.Cursors.Hand;
            ((Label)sender).Font = new System.Drawing.Font("宋体", 9F, System.Drawing.FontStyle.Underline, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
            ((Label)sender).ForeColor = Color.DeepSkyBlue;
        }

        private void lblValue_MouseLeave(object sender, EventArgs e)
        {
            ((Label)sender).Cursor = System.Windows.Forms.Cursors.Default;
            ((Label)sender).Font = new System.Drawing.Font("宋体", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
            ((Label)sender).ForeColor = Color.White;
        }

        private void lbl_ClearEqu_Click(object sender, EventArgs e)
        {
            dataGridView_GateWay.Rows.Clear();
        }

        private void lbl_ClearLocal_Click(object sender, EventArgs e)
        {
            lbxMsg.Items.Clear();
        }

        private void lbl_ClearPlatform_Click(object sender, EventArgs e)
        {
            txtLog.Text = "";
        }

        private void lbl_ClearSecair_Click(object sender, EventArgs e)
        {
            txtLogSecair.Text = "";
        }
        #endregion

    }
}
